package com.finance.cooperate.feature.service.impl;

import ch.qos.logback.core.joran.action.AppenderAction;
import com.finance.cooperate.common.constant.Constant;
import com.finance.cooperate.common.utils.DateUtils;
import com.finance.cooperate.common.utils.DigitalUtils;
import com.finance.cooperate.common.utils.StringUtil;
import com.finance.cooperate.dao.entity.primary.App;
import com.finance.cooperate.dao.local.cache.AppCategoryCache;
import com.finance.cooperate.dao.local.scope.CooperateRequestScope;
import com.finance.cooperate.dao.repository.primary.AppRepository;
import com.finance.cooperate.feature.dto.CompositeAppCountDTO;
import com.finance.cooperate.feature.params.AppListParams;
import com.finance.cooperate.feature.service.AppService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @ClassName AppServiceImpl
 * @Description TODO
 * @Author shen
 * @Date 2023/8/7 10:23
 * @Modify ...
 */
@Slf4j
@Service
public class AppServiceImpl implements AppService {

    @Autowired
    private AppRepository appRepository;

    @Autowired
    private CooperateRequestScope requestScope;

    @Override
    public CompositeAppCountDTO getCompositeAppCount(String uid, AppListParams params) {

        CompositeAppCountDTO dto = new CompositeAppCountDTO();

        // 跑特征取新数
        Date lastSubmitTime = requestScope.getLastSubmitTime();
//        Date lastSubmitTime = requestScope.getFirstLastSubmitTime();

        List<App> appList = appRepository.getCurrentApp(uid, requestScope.getDeviceId(), lastSubmitTime);

        // 基础信息
        dto = this.getBaseInfoFeature(dto, appList, lastSubmitTime);

        // 最近变化
        dto = this.getNearlyFeature(dto, appList, lastSubmitTime);


        // 竞品app细分【逾期率分】
        List<List<String>> competitionAppV1 = Arrays.asList(
                Arrays.asList("com.kaby", "com.tiri.mx", "com.lanai.ilana"),
                Arrays.asList("mx.app.vivus", "bonoup.prestamo.rapido", "com.presimex.credit", "loans.cash.convenience.viva.vida", "prestamo.efectivo.tala.superapoyo.credito.didi.rapido"),
                Arrays.asList("finance.empower.mx", "com.prestamx.max", "mx.com.tala", "com.prestamo.credito.dinero.efectivo.facil.rapido.noro", "com.baubap", "com.fiinlab.wallet"),
                Arrays.asList("com.molo.prestamo", "mx.credito.dinero.prestamo.miloan", "com.didiglobal.cashloan", "ai.powerup.stori"),
                Arrays.asList("com.mexicash.app", "com.fintopia.mxcredmex", "com.app.creditohucha")
        );

        Map<String, Integer> competitionV1 = this.getCompetitionAppLevel(appList, competitionAppV1, lastSubmitTime);

        dto.setCompetitionAppLevelV1(competitionV1.get("appLevel"));
        dto.setCompetitionAppLevel1CountV1(competitionV1.get("appLevel1Count"));
        dto.setCompetitionAppLevel2CountV1(competitionV1.get("appLevel2Count"));
        dto.setCompetitionAppLevel3CountV1(competitionV1.get("appLevel3Count"));
        dto.setCompetitionAppLevel4CountV1(competitionV1.get("appLevel4Count"));
        dto.setCompetitionAppLevel5CountV1(competitionV1.get("appLevel5Count"));


        // 安装量分
        List<List<String>> competitionAppV2 = Arrays.asList(
                Arrays.asList("mx.com.tala", "ai.powerup.stori", "credit.prestamos.personale.cash.efectivo"),
                Arrays.asList("com.palmpocket.cash.loan.app", "prestamos.joycredito.credito.pesos.peer2peermx", "com.mexicash.app", "com.pf.prestafast", "prestamos.creditoya.urgente.dinero.peso.cash.credito.rapido", "cash.meprestamo.tala.credito.oxxo.efectivo.okreditopeso.cashcash.prestamo", "com.okredito.cash.credito.tala.prestamo.ifectivo.prestaflash", "com.sggaanalista.okdinero", "com.fintopia.mxcredmex", "com.mexcoin.mx", "com.loan.cash.credit.tala.prestmo.fast.branch.mextamo", "com.sggaanalista.rapikredito", "cash.efectivo.okredito.prestamos.tala.credito.oxxo", "com.okredito.cash.credito.tala.prestamo.crediti"),
                Arrays.asList("com.credit.fectivocash.loan.cash.lending", "com.efectivo.prestamo", "com.lanai.ilana", "com.sggaanalista.cashmex", "com.super.dinero"),
                Arrays.asList("mx.amistad.cass", "loans.cash.convenience.viva.vida", "faith.assasin.creed.ezio", "com.molo.prestamo", "com.dinero.fd.mx.loan", "com.mexico.efectivo", "com.prestamo.credito.dinero.efectivo.facil.rapido.noro", "caudal.sube.credito", "com.tiri.mx", "finance.empower.mx", "wesharego.hope.zcydysja", "com.fiinlab.wallet", "moneda.come.creditoapp", "com.app.creditohucha", "pop.cash.org.tweaking.cm", "com.bobocredi.mx", "pesocash.loan.cash.prestamo.online", "mx.app.vivus"),
                Arrays.asList("com.prestamx.max", "com.presimex.credit", "mx.credito.dinero.prestamo.miloan", "com.app.dinero.hoy.loan.mx", "bonoup.prestamo.rapido", "com.niuhai.market", "com.kaby", "com.apoyoro.mx", "rapido.presta.cash", "com.cash.kualis.tala.prestamo.baubap.rapido.dinero", "sta.bilny.zaem", "prestamo.efectivo.tala.superapoyo.credito.didi.rapido")
        );

        Map<String, Integer> competitionV2 = this.getCompetitionAppLevel(appList, competitionAppV2, lastSubmitTime);

        dto.setCompetitionAppLevelV2(competitionV2.get("appLevel"));
        dto.setCompetitionAppLevel1CountV2(competitionV2.get("appLevel1Count"));
        dto.setCompetitionAppLevel2CountV2(competitionV2.get("appLevel2Count"));
        dto.setCompetitionAppLevel3CountV2(competitionV2.get("appLevel3Count"));
        dto.setCompetitionAppLevel4CountV2(competitionV2.get("appLevel4Count"));
        dto.setCompetitionAppLevel5CountV2(competitionV2.get("appLevel5Count"));

        dto.setCompetitionAppLevel3To5CountV2(competitionV2.get("appLevel3Count") + competitionV2.get("appLevel4Count") + competitionV2.get("appLevel5Count"));

        // APP 安装统计
        // ==》是否安装
        Map<String, Long> installMapV1 = this.getInstallMap(appList, params.getAppSetV1());
        dto.setAppIsInstallV1(installMapV1);

        // ==》安装时间
        Map<String, Long> timeMapV1 = this.getInstallTimeMap(appList, params.getAppSetV1(), lastSubmitTime, Constant.APP_TIME_PARTITION_ARR_01);
        dto.setAppInstallTimeV1(timeMapV1);

        Map<String, Long> retentiveTimeMap = this.getRetentiveTimeMap(appList, params.getRetentiveSet(), lastSubmitTime);
        dto.setAppRetentiveTime(retentiveTimeMap);

        return dto;
    }




    /**
     * @Author shen
     * @Description app 留存时间类特征
     * @Date 22:52 2023/8/7
     * @Param [appList, appSet, lastSubmitTime]
     * @return java.util.Map<java.lang.String,java.lang.Long>
     **/
    private Map<String, Long> getRetentiveTimeMap(List<App> appList, Set<String> appSet, Date lastSubmitTime) {

        Map<String, Long> result = new HashMap<>();

        try {

            if (appList.size() > 0) {

                // 防止多次遍历
                Map<String, String> appPackageMap = new HashMap<>();
                for (App app: appList) {
                    String packageName = app.getAppPackageName();
                    appPackageMap.put(packageName.toLowerCase(), app.getFirstInstallTime());
                }


                for (String set : appSet) {

                    Long installTimeDays = Constant.MISSING_VALUE;

                    if (appPackageMap.containsKey(set.toLowerCase())) {

                        String installTimeStr = appPackageMap.get(set.toLowerCase());
                        Date installTime = DateUtils.toDate(installTimeStr);

                        Integer diffDays = DateUtils.getTimeDiffDays(installTime, lastSubmitTime);

                        installTimeDays = Long.valueOf(diffDays);

                    }

                    result.put(set, installTimeDays);

                }


            }

        } catch (Exception e) {
            log.error(e.toString(), e);
        }



        return result;

    }



    /**
     * @Author shen
     * @Description app 安装时间类特征
     * @Date 22:41 2023/8/7
     * @Param [appList, appSet, lastSubmitTime, arr]
     * @return java.util.Map<java.lang.String,java.lang.Long>
     **/
    private Map<String, Long> getInstallTimeMap(List<App> appList, Set<String> appSet, Date lastSubmitTime, int[] arr) {

        Map<String, Long> appInstallTime = new HashMap<>();

        try {

            if (appList.size() > 0) {

                // 防止多次遍历
                Map<String, String> appPackageMap = new HashMap<>();
                for (App app: appList) {
                    String packageName = app.getAppPackageName();
                    appPackageMap.put(packageName.toLowerCase(), app.getFirstInstallTime());
                }


                for (String set : appSet) {

                    Long installTimeDays = Constant.MISSING_VALUE;

                    if (appPackageMap.containsKey(set.toLowerCase())) {

                        String installTimeStr = appPackageMap.get(set.toLowerCase());
                        Date installTime = DateUtils.toDate(installTimeStr);

                        Integer diffDays = DateUtils.getTimeDiffDays(installTime, lastSubmitTime);

                        installTimeDays = Long.valueOf(diffDays);

                    }


                    if (installTimeDays > 0) {

                        int value = DigitalUtils.appInstallTimeConvert(arr, installTimeDays.intValue());

                        appInstallTime.put(set + "_" + value, Constant.IS_HIT);

                    }
                }
            }

        } catch (Exception e) {
            log.error(e.toString(), e);
        }

        return appInstallTime;
    }


    /**
     * @Author shen
     * @Description app 安装类特征
     * @Date 22:16 2023/8/7
     * @Param [appList, appSet]
     * @return java.util.Map<java.lang.String,java.lang.Long>
     **/
    private Map<String, Long> getInstallMap(List<App> appList, Set<String> appSet) {

        // APP 安装统计
        Map<String, Long> appIsInstall = new HashMap<>();

        try {

            if (appList.size() > 0) {

                // 防止多次遍历
                Set<String> appPackageSet = new HashSet<>();
                for (App app: appList) {
                    String packageName = app.getAppPackageName();
                    appPackageSet.add(packageName.toLowerCase());
                }


                for (String set: appSet) {

                    long isInstall = Constant.IS_NO_HIT;

                    if (appPackageSet.contains(set.toLowerCase())) {
                        isInstall = Constant.IS_HIT;
                    }

                    appIsInstall.put(set, isInstall);

                }


            }


        } catch (Exception e) {
            log.error(e.toString(), e);
        }

        return appIsInstall;

    }


    /**
    * @Author shenanxin
    * @Description 根据安装量筛选
    * @Date 09:38 2023/9/20
    * @Param [appList, lastSubmitTime]
    * @return java.util.Map<java.lang.String,java.lang.Integer>
    **/
    private Map<String, Integer> getCompetitionAppLevel (List<App> appList, List<List<String>> competitionAppList,  Date lastSubmitTime) {

        Integer appLevel = 0;

        Integer appLevel1Count = 0;
        Integer appLevel2Count = 0;
        Integer appLevel3Count = 0;
        Integer appLevel4Count = 0;
        Integer appLevel5Count = 0;

        for (App app : appList) {

            String packageName = app.getAppPackageName();

            if (competitionAppList.get(0).contains(packageName)) {

                if (appLevel1Count >= 0) {
                    appLevel1Count ++;
                } else {
                    appLevel1Count = 1;
                }

            } else if (competitionAppList.get(1).contains(packageName)) {

                if (appLevel2Count >= 0) {
                    appLevel2Count ++;
                } else {
                    appLevel2Count = 1;
                }

            } else if (competitionAppList.get(2).contains(packageName)) {

                if (appLevel3Count >= 0) {
                    appLevel3Count ++;
                } else {
                    appLevel3Count = 1;
                }

            } else if (competitionAppList.get(3).contains(packageName)) {

                if (appLevel4Count >= 0) {
                    appLevel4Count ++;
                } else {
                    appLevel4Count = 1;
                }

            } else if (competitionAppList.get(4).contains(packageName)) {

                if (appLevel5Count >= 0) {
                    appLevel5Count ++;
                } else {
                    appLevel5Count = 1;
                }

            }

        }

        if (appLevel1Count > 0) {
            appLevel = 1;
        } else if (appLevel2Count > 0) {
            appLevel = 2;
        } else if (appLevel3Count > 0) {
            appLevel = 3;
        } else if (appLevel4Count > 0) {
            appLevel = 4;
        } else if (appLevel5Count > 0) {
            appLevel = 5;
        }

        Map<String, Integer> appLevels = new HashMap<String, Integer>();
        appLevels.put("appLevel", appLevel);
        appLevels.put("appLevel1Count", appLevel1Count);
        appLevels.put("appLevel2Count", appLevel2Count);
        appLevels.put("appLevel3Count", appLevel3Count);
        appLevels.put("appLevel4Count", appLevel4Count);
        appLevels.put("appLevel5Count", appLevel5Count);


        return appLevels;
    }

    /**
     * @Author shen
     * @Description 基本信息特征
     * @Date 10:29 2023/8/7
     * @Param [dto, appList, lastSubmitTime]
     * @return com.finance.cooperate.feature.dto.CompositeAppCountDTO
     **/
    private CompositeAppCountDTO getBaseInfoFeature(CompositeAppCountDTO dto, List<App> appList, Date lastSubmitTime) {

        dto.setAppCount(appList.size());

        Integer loanTop10Count = null, loanTop10DistanceSubmitTimeDaysAvg = null, loanTop10DistanceSubmitTimeDaysMax = null,
                loanTop30Count = null, loanTop30DistanceSubmitTimeDaysAvg = null, loanTop30DistanceSubmitTimeDaysMax = null,
                loanTop60Count = null, loanTop60DistanceSubmitTimeDaysAvg = null, loanTop60DistanceSubmitTimeDaysMax = null
                ;


        Integer hasChineseCount = null;

        try {

            loanTop10Count = loanTop10DistanceSubmitTimeDaysAvg = loanTop10DistanceSubmitTimeDaysMax
                    = loanTop30Count = loanTop30DistanceSubmitTimeDaysAvg = loanTop30DistanceSubmitTimeDaysMax
                    = loanTop60Count = loanTop60DistanceSubmitTimeDaysAvg = loanTop60DistanceSubmitTimeDaysMax
                    = 0;

            Integer sumLoanTop10Day = 0;
            Integer sumLoanTop30Day = 0;
            Integer sumLoanTop60Day = 0;

            hasChineseCount = 0;

            for (App app : appList) {


                String appName = app.getAppName();

                if (StringUtil.hasChinese(appName)) {
                    hasChineseCount ++;
                }

                String installTimeStr = app.getFirstInstallTime();

                Date installTime = DateUtils.toDate(installTimeStr);

                String packageName = app.getAppPackageName();

                Integer nowadays = DateUtils.getTimeDiffDays(installTime, lastSubmitTime);

                if (nowadays == null || nowadays < 0) {
                    continue;
                }

                if (AppCategoryCache.isLoanTop10App(packageName)) {
                    loanTop10Count ++;


                    if (loanTop10DistanceSubmitTimeDaysMax < nowadays) {
                        loanTop10DistanceSubmitTimeDaysMax = nowadays;
                    }

                    sumLoanTop10Day += nowadays;

                }

                if (AppCategoryCache.isLoanTop30App(packageName)) {
                    loanTop30Count ++;

                    if (loanTop30DistanceSubmitTimeDaysMax < nowadays) {
                        loanTop30DistanceSubmitTimeDaysMax = nowadays;
                    }

                    sumLoanTop30Day += nowadays;

                }

                if (AppCategoryCache.isLoanTop60App(packageName)) {
                    loanTop60Count ++;

                    if (loanTop60DistanceSubmitTimeDaysMax < nowadays) {
                        loanTop60DistanceSubmitTimeDaysMax = nowadays;
                    }

                    sumLoanTop60Day += nowadays;

                }


            }

            if (loanTop10Count > 0) {
                loanTop10DistanceSubmitTimeDaysAvg = sumLoanTop10Day / loanTop10Count;
            }

            if (loanTop30Count > 0) {
                loanTop30DistanceSubmitTimeDaysAvg = sumLoanTop30Day / loanTop30Count;
            }

            if (loanTop60Count > 0) {
                loanTop60DistanceSubmitTimeDaysAvg = sumLoanTop60Day / loanTop60Count;
            }



        } catch (Exception e) {
            log.error(e.toString(), e);
        }


        dto.setLoanTop10Count(loanTop10Count);
        dto.setLoanTop10DistanceSubmitTimeDaysAvg(loanTop10DistanceSubmitTimeDaysAvg);
        dto.setLoanTop10DistanceSubmitTimeDaysMax(loanTop10DistanceSubmitTimeDaysMax);


        dto.setLoanTop30Count(loanTop30Count);
        dto.setLoanTop30DistanceSubmitTimeDaysAvg(loanTop30DistanceSubmitTimeDaysAvg);
        dto.setLoanTop30DistanceSubmitTimeDaysMax(loanTop30DistanceSubmitTimeDaysMax);


        dto.setLoanTop60Count(loanTop60Count);
        dto.setLoanTop60DistanceSubmitTimeDaysAvg(loanTop60DistanceSubmitTimeDaysAvg);
        dto.setLoanTop60DistanceSubmitTimeDaysMax(loanTop60DistanceSubmitTimeDaysMax);

        dto.setHasChineseCount(hasChineseCount);


        return dto;

    }

    /**
     * @Author shen
     * @Description 近期变化类特征
     * @Date 22:01 2023/8/7
     * @Param [dto, appList, lastSubmitTime]
     * @return com.finance.cooperate.feature.dto.CompositeAppCountDTO
     **/
    private CompositeAppCountDTO getNearlyFeature(CompositeAppCountDTO dto, List<App> appList, Date lastSubmitTime) {

        Integer nearly1MonthsAppCount = null;
        Integer nearly2MonthsAppCount = null;
        Integer nearly3MonthsAppCount = null;

        Double  nearly1MonthsAppPercentage = null;
        Double  nearly2MonthsAppPercentage = null;
        Double  nearly3MonthsAppPercentage = null;

        Integer firstAppInstallDays = null;
        Integer lastAppInstallDays = null;

        try {

            if (appList.size() > 0) {

                nearly1MonthsAppCount = 0;
                nearly2MonthsAppCount = 0;
                nearly3MonthsAppCount = 0;

                int appCount = 0;

                for (App app : appList) {

                    String installTimeStr = app.getFirstInstallTime();

                    Date installTime = DateUtils.toDate(installTimeStr);

                    Integer diffDays = DateUtils.getTimeDiffDays(installTime, lastSubmitTime);

                    if (diffDays == null || diffDays < 0) {
                        continue;
                    }

                    if (firstAppInstallDays == null || firstAppInstallDays < diffDays) {
                        firstAppInstallDays =  diffDays;

                    }

                    if (lastAppInstallDays == null || lastAppInstallDays > diffDays) {
                        lastAppInstallDays = diffDays;
                    }

                    if (diffDays <= 3*30) {
                        nearly3MonthsAppCount ++;

                        if (diffDays <= 2*30) {
                            nearly2MonthsAppCount ++;

                            if (diffDays <= 30) {
                                nearly1MonthsAppCount ++;
                            }

                        }

                    }

                    appCount ++;


                }

                nearly3MonthsAppPercentage = (double) nearly3MonthsAppCount.intValue() / appCount;
                nearly2MonthsAppPercentage = (double) nearly2MonthsAppCount.intValue() / appCount;
                nearly1MonthsAppPercentage = (double) nearly1MonthsAppCount.intValue() / appCount;

            }


        } catch (Exception e) {
            log.error(e.toString(), e);
        }

        dto.setNearly1MonthsAppCount(nearly1MonthsAppCount);
        dto.setNearly2MonthsAppCount(nearly2MonthsAppCount);
        dto.setNearly3MonthsAppCount(nearly3MonthsAppCount);
        dto.setNearly1MonthsAppPercentage(nearly1MonthsAppPercentage);
        dto.setNearly2MonthsAppPercentage(nearly2MonthsAppPercentage);
        dto.setNearly3MonthsAppPercentage(nearly3MonthsAppPercentage);
        dto.setFirstAppInstallDays(firstAppInstallDays);
        dto.setLastAppInstallDays(lastAppInstallDays);

        return dto;

    }

}
